import java.util.*;
import java.io.*;
import java.security.MessageDigest;
import com.evernote.edam.type.*;
import com.evernote.edam.userstore.*;
import com.evernote.edam.error.EDAMErrorCode;
import com.evernote.edam.error.EDAMUserException;
import com.evernote.edam.notestore.*;
import com.facebook.thrift.*;
import com.facebook.thrift.protocol.TBinaryProtocol;
import com.facebook.thrift.transport.THttpClient;

public class EDAMDemo {

	public static void main(String args[]) throws Exception {

		try {
			String username = "rhynolite";
			String password = "mercurypw";
			String consumerKey = "rhynolite";
			String consumerSecret = "b8433c8074bfa9af";
			String userStoreUrl = "https://sandbox.evernote.com/edam/user";
			String noteStoreUrlBase = "http://sandbox.evernote.com/edam/note/";

			// Set up the UserStore and check that we can talk to the server
			THttpClient userStoreTrans = new THttpClient(userStoreUrl);
			TBinaryProtocol userStoreProt = new TBinaryProtocol(userStoreTrans);
			UserStore.Client userStore = new UserStore.Client(userStoreProt,
					userStoreProt);
			boolean versionOk = userStore.checkVersion(
					"Dave's EDAMDemo (Java)",
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
			if (!versionOk) {
				System.err.println("Incomatible EDAM client protocol version");
				return;
			}

			// Authenticate as a user & password
			AuthenticationResult authResult = userStore.authenticate(username,
					password, consumerKey, consumerSecret);
			User user = authResult.getUser();
			String authToken = authResult.getAuthenticationToken();

			// Set up the NoteStore
			System.out.println("Notes for " + user.getUsername() + ":");
			String noteStoreUrl = noteStoreUrlBase + user.getShardId();
			THttpClient noteStoreTrans = new THttpClient(noteStoreUrl);
			TBinaryProtocol noteStoreProt = new TBinaryProtocol(noteStoreTrans);
			NoteStore.Client noteStore = new NoteStore.Client(noteStoreProt,
					noteStoreProt);

			// List all of the notes in the account
			List<Notebook> notebooks = (List<Notebook>) noteStore
					.listNotebooks(authToken);
			Notebook defaultNotebook = notebooks.get(0);
			for (Notebook notebook : notebooks) {
				System.out.println("Notebook: " + notebook.getName());
				NoteFilter filter = new NoteFilter();
				filter.setNotebookGuid(notebook.getGuid());
				NoteList noteList = noteStore.findNotes(authToken, filter, 0,
						100);
				List<Note> notes = (List<Note>) noteList.getNotes();
				for (Note note : notes) {
					System.out.println(" * " + note.getTitle());
				}
				if (notebook.isDefaultNotebook()) {
					defaultNotebook = notebook;
				}
			}

			// Create a note containing a little text, plus the "enlogo.png"
			// image
			Resource resource = new Resource();
			resource.setData(readFileAsData("enlogo.png"));
			resource.setMime("image/png");
			Note note = new Note();
			note.setTitle("Test note from EDAMDemo");
			note.setCreated(System.currentTimeMillis());
			note.setUpdated(System.currentTimeMillis());
			note.setActive(true);
			note.setNotebookGuid(defaultNotebook.getGuid());
			note.addToResources(resource);
			String hashHex = bytesToHex(resource.getData().getBodyHash());
			String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
					+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
					+ "<en-note>Here's the Evernote logo:<br/>"
					+ "<en-media type=\"image/png\" hash=\"" + hashHex + "\"/>"
					+ "</en-note>";
			note.setContent(content);
			Note createdNote = noteStore.createNote(authToken, note);
			System.out.println("Note created. GUID: " + createdNote.getGuid());

		} catch (EDAMUserException e) {
			String desc = null;
			int errorCode = e.getErrorCode();
			switch (errorCode) {
			case EDAMErrorCode.UNKNOWN:
				desc = "No information available about the error";
				break;
			case EDAMErrorCode.BAD_DATA_FORMAT:
				desc = "The format of the request data was incorrect";
				break;
			case EDAMErrorCode.PERMISSION_DENIED:
				desc = "Not permitted to perform action";
				break;
			case EDAMErrorCode.INTERNAL_ERROR:
				desc = "Unexpected problem with the service";
				break;
			case EDAMErrorCode.DATA_REQUIRED:
				desc = "A required parameter/field was absent";
				break;
			case EDAMErrorCode.LIMIT_REACHED:
				desc = "Operation denied due to data model limit";
				break;
			case EDAMErrorCode.QUOTA_REACHED:
				desc = "Operation denied due to user storage limit";
				break;
			case EDAMErrorCode.INVALID_AUTH:
				desc = "Username and/or password incorrect";
				break;
			case EDAMErrorCode.AUTH_EXPIRED:
				desc = "Authentication token expired";
				break;
			case EDAMErrorCode.DATA_CONFLICT:
				desc = "Change denied due to data model conflict";
				break;
			case EDAMErrorCode.ENML_VALIDATION:
				desc = "Content of submitted note was malformed";
				break;
			case EDAMErrorCode.SHARD_UNAVAILABLE:
				desc = "Service shard with account data is temporarily down";
				break;
			default:
				desc = "meh";
			}
			System.out.println("Caugth user exception " + e + "; eror code: "
					+ errorCode + "; " + desc);

		}
	}

	private static Data readFileAsData(String fileName) throws Exception {
		FileInputStream in = new FileInputStream(fileName);
		ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
		byte[] block = new byte[10240];
		int len;
		while ((len = in.read(block)) >= 0) {
			byteOut.write(block, 0, len);
		}
		in.close();
		byte[] body = byteOut.toByteArray();
		Data data = new Data();
		data.setSize(body.length);
		data.setBodyHash(MessageDigest.getInstance("MD5").digest(body));
		data.setBody(body);
		return data;
	}

	public static String bytesToHex(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte hashByte : bytes) {
			int intVal = 0xff & hashByte;
			if (intVal < 0x10) {
				sb.append('0');
			}
			sb.append(Integer.toHexString(intVal));
		}
		return sb.toString();
	}

}
